package com.learning.springmvc.advance.view.config;

import com.google.common.collect.Lists;
import com.learning.springmvc.advance.view.bean.User;
import com.learning.springmvc.advance.view.view.ExcelView;
import com.learning.springmvc.advance.view.view.PdfView;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.freemarker.FreeMarkerConfigurationFactory;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.BeanNameViewResolver;
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.XmlViewResolver;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerView;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
import org.springframework.web.servlet.view.xml.MarshallingView;

/**
 * ClassName: WebMvcConfig
 * Description: Spring MVC 配置 继承自{@link WebMvcConfigurerAdapter}。可以理解为 WebApplicationContext 容器的配置
 * <p>
 * Date: 2019/5/13 15:46 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.learning.springmvc.advance", useDefaultFilters = false,
        includeFilters = {@ComponentScan.Filter(classes = Controller.class)})
public class WebMvcConfig extends WebMvcConfigurerAdapter {


    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        super.addViewControllers(registry);
    }

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.viewResolver(beanNameViewResolver());

//        registry.jsp("/WEB-INF/view/", ".jsp");
        registry.viewResolver(internalResourceViewResolver());

//        registry.freeMarker();
//        registry.viewResolver(freeMarkerViewResolver());

        // 混合视图解析器
        registry.enableContentNegotiation(jsonView(), xmlView());

    }

    /**
     * 默认使用 InternalResourceView 视图解析器
     * 使用 InternalResourceView 或者 JstlView 视图类型
     *
     * @return
     */
    public InternalResourceViewResolver internalResourceViewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/view/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

    /**
     * 默认使用 FreeMarkerView 视图
     *
     * @return
     */
    public FreeMarkerViewResolver freeMarkerViewResolver() {
        FreeMarkerViewResolver viewResolver = new FreeMarkerViewResolver();
        viewResolver.setViewClass(FreeMarkerView.class);
        // 不能设置，会报错
//        viewResolver.setPrefix("/WEB-INF/view/");
        viewResolver.setSuffix(".ftl");
        // 提高优先级
        viewResolver.setOrder(5);
        viewResolver.setContentType("text/html;charset=UTF-8");
        return viewResolver;
    }

    /**
     * FreeMarkerConfigurer 配置属性
     *
     * @return
     */
    @Bean
    public FreeMarkerConfigurer freeMarkerConfigurer() {
        FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
        applyProperties(configurer);
        return configurer;
    }

    protected void applyProperties(FreeMarkerConfigurationFactory factory) {
        // 模板文件存放路径
        factory.setTemplateLoaderPaths("/WEB-INF/view/");
        factory.setPreferFileSystemAccess(true);
        factory.setDefaultEncoding("UTF-8");
//        Properties settings = new Properties();
        // null对象属性非异常处理
//        settings.put("classic_compatible", true);
//        factory.setFreemarkerSettings(settings);
    }

    /**
     * 定义BeanNameViewResolver视图解析器，为Excel视图服务
     *
     * @return
     */
    public BeanNameViewResolver beanNameViewResolver() {
        BeanNameViewResolver beanNameViewResolver = new BeanNameViewResolver();
        beanNameViewResolver.setOrder(10);
        return beanNameViewResolver;
    }

    /**
     * 配置Excel视图对象
     *
     * @return
     */
    @Bean
    public ExcelView excelView() {
        return new ExcelView();
    }

    /**
     * 配置PDF视图对象
     *
     * @return
     */
    @Bean
    public PdfView pdfView() {
        return new PdfView();
    }


    /**
     * 定义 XML 视图
     * 使用 Jaxb2Marshaller 解析，需要添加注解 @XmlRootElement(name = "user")
     *
     * @return
     */
    @Bean
    public MarshallingView xmlView() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setClassesToBeBound(User.class);
        MarshallingView marshallingView = new MarshallingView(marshaller);
        // 指定模型中的属性
        marshallingView.setModelKey("user");
        return marshallingView;
    }

    @Bean
    public MappingJackson2JsonView jsonView() {
        MappingJackson2JsonView mappingJackson2JsonView = new MappingJackson2JsonView();
        mappingJackson2JsonView.setModelKey("user");
        return mappingJackson2JsonView;
    }

    /**
     * 一般来说，视图对象的Bean数目太多，可以使用 XmlViewResolver 独立配置
     * 默认的独立配置文件为：/WEB-INF/views.xml，可以通过 location 属性显示指定
     * 这个配置文件中的Bean，不能被上下文的其他Bean引用，被解析器独享
     *
     * @return
     */
//    @Bean
    public XmlViewResolver xmlViewResolver() {
        XmlViewResolver xmlViewResolver = new XmlViewResolver();
        xmlViewResolver.setLocation(new ClassPathResource(""));
        return xmlViewResolver;
    }

    /**
     * 混合视图解析器
     *
     * @param manager
     * @return
     */
//    @Bean
    public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {
        ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
        resolver.setContentNegotiationManager(manager);

        resolver.setDefaultViews(Lists.newArrayList(jsonView(), xmlView()));
        return resolver;
    }

    /**
     * 扩展 ContentNegotiationManager 属性
     *
     * @param configurer
     */
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        // 属性默认为true，这根据URL中的文件扩展名确定MIME类型（user.json）
        configurer.favorPathExtension(true);
        // 属性设置为true，则根据请求参数的值确定MIME类型。
        // 默认的请求参数是 format，可以通过 parameterName 属性指定一个自定义参数
        configurer.favorParameter(false);
        configurer.parameterName("format");
        // 属性默认为false，采用Accept-Header的值确定MIME类型
        configurer.ignoreAcceptHeader(true);
    }


}
